package logger

import (
	"gitee.com/igolang/pkg/xcfg"
	"gitee.com/igolang/pkg/xlog"
	"gitee.com/igolang/pkg/xset"
	"gitee.com/igolang/pkg/xutils"
	"github.com/pkg/errors"
	"log/slog"
	"os"
	"path/filepath"
	"slices"
	"strings"
	"sync"
)

const (
	DefaultLoggerName = "default"
)

var defaultLogger = xlog.Default()

var Logger = &loggers{
	logs: make(map[string]*slog.Logger),
}

type loggers struct {
	logs map[string]*slog.Logger
	sync.RWMutex
}

func (c *loggers) add(name string, logger *slog.Logger) {
	c.Lock()
	defer c.Unlock()
	c.logs[name] = logger
	return
}

func (c *loggers) get(name string) *slog.Logger {
	c.RLock()
	defer c.RUnlock()
	return c.logs[name]
}

func (c *loggers) formatLevel(in string) slog.Leveler {
	levelMap := map[string]slog.Leveler{
		"debug": slog.LevelDebug,
		"info":  slog.LevelInfo,
		"warn":  slog.LevelWarn,
		"error": slog.LevelError,
	}
	level, ok := levelMap[in]
	if !ok {
		level = slog.LevelDebug
	}
	return level
}

func (c *loggers) formatPaths(paths []string) []string {
	if len(paths) == 0 {
		return paths
	}
	list := make([]string, 0)
	for _, v := range paths {
		if slices.Contains([]string{"stdout", "stderr"}, strings.ToLower(v)) {
			list = append(list, v)
			continue
		}
		if filepath.IsAbs(v) {
			list = append(list, v)
			continue
		}
		logDir := filepath.Join(xutils.CurrentAbPath(), "logs")
		if !xutils.FileExists(logDir) {
			if err := os.Mkdir(logDir, 0750); err != nil {
				panic(err)
			}
		}
		filename := filepath.Join(logDir, v)
		list = append(list, filename)
	}

	return xset.New(list...).Values()
}

func (c *loggers) Name() string {
	return "loggers"
}

func (c *loggers) Init() error {
	if !xcfg.IsSet("log") {
		return errors.New("log config nil")
	}
	cfg := &xlog.Config{
		OutputPaths: c.formatPaths(xcfg.GetStringSlice("log.outputPaths")),
		Format:      xcfg.GetString("log.format"),
		ErrPaths:    c.formatPaths(xcfg.GetStringSlice("log.errLogPaths")),
	}
	cfg.AddSource = xcfg.GetBool("log.dev")
	// 处理日志级别
	cfg.Level = c.formatLevel(xcfg.GetString("log.level"))
	// 实例化
	logger, err := xlog.New(cfg)
	if err != nil {
		return err
	}
	logger = logger.With("ext", map[string]interface{}{
		"app": xcfg.GetString("name"),
		"env": xcfg.GetString("env"),
	})
	c.add(DefaultLoggerName, logger)
	defaultLogger = logger
	return nil
}

func (c *loggers) Shutdown() error {
	return nil
}

func Log(name ...string) *slog.Logger {
	if len(name) == 0 {
		return defaultLogger
	}

	l := Logger.get(name[0])
	if l == nil {
		l = xlog.Default()
	}

	return l
}

func SetLog(name string, logger *slog.Logger) {
	Logger.add(name, logger)
}
